
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>

#define UNIXSTR_PATH "/tmp/unix_stream.sock"

int main(void)
{

    int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket error:　");
        exit(EXIT_FAILURE);
    }

    int ret = unlink(UNIXSTR_PATH);
    if (ret == -1)
    {
        perror("unlink error: ");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_un serverAddr;
    int addrLen = sizeof(serverAddr);
    memset(&serverAddr, 0, addrLen);
    serverAddr.sun_family = AF_LOCAL;
    strcpy(serverAddr.sun_path, UNIXSTR_PATH);

    if (bind(sockfd, (struct sockaddr *)&serverAddr, addrLen) == -1)
    {
        perror("bind error: ");
        exit(EXIT_FAILURE);
    }

    if (listen(sockfd, 5) == -1)
    {
        perror("listen error: ");
        exit(EXIT_FAILURE);
    }

    fd_set rfds, allfds;
    FD_ZERO(&rfds);
    FD_ZERO(&allfds);
    FD_SET(sockfd, &allfds);
    int maxfd = sockfd;

    int nready;
    int cfds[5] = {-1};
    int i = 0;
    while (1)
    {
        rfds = allfds;
        if ((nready = select(maxfd + 1, &rfds, NULL, NULL, NULL)) == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                perror("Select error: ");
                exit(EXIT_FAILURE);
            }
        }
        else if (nready == 0)
        {
            continue;
        }

        if (FD_ISSET(sockfd, &rfds))
        {
            int conn = accept(sockfd, NULL, NULL);
            if (conn == -1)
            {
                perror("accept error: ");
                exit(EXIT_FAILURE);
            }

            for (i = 0; i < 5; ++i)
            {
                if (cfds[i] == -1)
                {
                    cfds[i] = conn;
                    break;
                }
            }

            if (i == 5)
            {
                close(conn);
            }
            else
            {
                FD_SET(cfds[i], &allfds);
                if (cfds[i] > maxfd)
                {
                    maxfd = cfds[i];
                }
            }
        }

        for (i = 0; i < 5; ++i)
        {
            if (cfds[i] == -1)
            {
                continue;
            }

            if (FD_ISSET(cfds[i], &rfds))
            {
                char buff[1024] = {0};
                int ret = read(cfds[i], buff, 1024);
                if (ret == -1)
                {
                    perror("read error: ");
                }
                else if (ret == 0)
                {
                    FD_CLR(cfds[i], &allfds);
                    cfds[i] = -1;
                    close(cfds[i]);
                }
                else
                {
                    printf("%s\n", buff);
                    write(cfds[i], buff, ret);
                }
            }
        }
    }

    return 0;
}